#include "board.h"
#include <ti/sysbios/knl/Semaphore.h>
#include <xdc/std.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/uart/UARTCC26XX.h>
#include <ti/sysbios/knl/Semaphore.h>
#include "hal_types.h"
#include "util_timer.h"
#include "zstack.h"
#include "zstackapi.h"

#include "cmd.h"
#include "cmd_cfg.h"
#include "cmd_pkt.h"
#include "zglobals.h"
#include "zcomdef.h"
#include "osal_nv.h"

/* extern variable */
extern uint8_t cmdPktTaskId;

void cmdCfg_DeviceType(uint8_t *cmd, uint8 len);
uint8_t  cmdCfg_Status(void);
uint8_t  cmdCfg_Channel(bool set, uint8_t ch, uint32_t *chList);
uint8_t  cmdCfg_Start(void);
uint8_t  cmdCfg_Scan(uint32_t channel, uint8_t duration);

void cmdCfg_CmdInput(uint8_t cmdSeq, uint8_t cmdClass, uint8_t cmdLen, uint8_t* cmdData)
{
  uint8_t cmdId = cmdData[0];
  uint8_t *p = cmdData + 1;
  uint8_t ackLen = 0;
  uint8_t acbBuff[128];
  uint8_t *pAck = acbBuff + 1;
  uint8_t status = ZFailure;
  switch(cmdId)
  {
  case CFG_CMD_STATUS:
    {
      status = cmdCfg_Status();
    }
    break;
    
  case CFG_CMD_CHANNEL:
    {
      bool set = p[0];
      uint32_t ch;
      status = cmdCfg_Channel(set, p[1], &ch);
      if(status == ZSuccess)
      {
        pAck[0] = BREAK_UINT32(ch, 0);
        pAck[1] = BREAK_UINT32(ch, 1);
        pAck[2] = BREAK_UINT32(ch, 2);
        pAck[3] = BREAK_UINT32(ch, 3);
        ackLen += 4;
      }
    }
    break;
    
  case CFG_CMD_START:
    {
      status = cmdCfg_Start();
    }
    
  case CFG_CMD_SCAN:
    {
      uint32_t channel = BUILD_UINT32(p[0], p[1], p[2], p[3]);
      uint8_t duration = p[4];
      status = cmdCfg_Scan(channel, duration);
    }
    break;
    
  default:
    break;
  }
  ackLen += 1;
  acbBuff[0] = status;
  CmdPkt_AckSend(cmdSeq,cmdClass,ackLen,acbBuff);
}

void cmdCfg_CmdOutput(uint8_t cmdId, uint8_t len, uint8_t* data)
{
  uint8_t buf[128];
  buf[0] = CmdPkt_GetSeqNum();
  buf[1] = CMD_CLASS_STATUS;
  buf[2] = cmdId;
  
  memcpy( buf+3, data, len );
  CmdPkt_TxSend( len+3, buf );
}


/*
  Command print
*/
void cmdCfg_CoordStartNotify(uint8_t sta, uint8_t channel, uint16_t panId)
{
  uint8_t buf[4];
  buf[0] = sta;
  buf[1] = channel;
  buf[2] = LO_UINT16(panId);
  buf[3] = HI_UINT16(panId);
  cmdCfg_CmdOutput(CFG_CMD_NWK_START, 4, buf);
}

void cmdCfg_PermitJoinNotify(uint8_t time)
{
  cmdCfg_CmdOutput(CFG_CMD_PERMIT, 1, &time);
}

  
void cmdCfg_BeaconIndNotify(uint16_t panId, uint16_t nodeId, uint8_t channel)
{
  
}

void cmdCfg_ScanEnd(void)
{
  
}

void cmdCfg_NodeJoinNotify(uint8_t* mac, uint16_t nodeId, uint8_t mode, uint8_t type)
{
  uint8_t buf[12];
  memcpy(buf, mac, 8);
  buf[8] = LO_UINT16(nodeId);
  buf[9] = HI_UINT16(nodeId);
  buf[10] = mode;
  buf[11] = type;
  cmdCfg_CmdOutput(CFG_CMD_NODE_JOIN, 12, buf);
}

void cmdCfg_DevJoinNotify(mfgDevSn_t sn, mfgDevAddr_t dev, uint16_t profile, uint16_t devId,
                          uint8_t inNum, uint16_t *inCluster, uint8_t outNum, uint16_t *outCluster)
{
  uint8_t buf[80];
  uint8_t len = 0;
  uint8_t *p = buf;
  uint8_t n;

  memcpy(p, sn, sizeof(mfgDevSn_t));
  p += sizeof(mfgDevSn_t);
  len += sizeof(mfgDevSn_t);

  memcpy(p, dev, sizeof(mfgDevAddr_t));
  p += sizeof(mfgDevAddr_t);
  len += sizeof(mfgDevAddr_t);

  *p++ = LO_UINT16(profile);
  *p++ = HI_UINT16(profile);
  len += 2;

  *p++ = LO_UINT16(devId);
  *p++ = HI_UINT16(devId);
  len += 2;

  *p++ = inNum;
  for(n=0;n<inNum;n++)
  {
    *p++ = LO_UINT16(inCluster[n]);
    *p++ = HI_UINT16(inCluster[n]);
    len += 2;
  }

  *p++ = outNum;
  for(n=0;n<outNum;n++)
  {
    *p++ = LO_UINT16(outCluster[n]);
    *p++ = HI_UINT16(outCluster[n]);
    len += 2;
  }

  cmdCfg_CmdOutput(CFG_CMD_DEVICE_JOIN, len, buf);
}

/*
 * Command config
 */
void cmdCfg_DeviceType(uint8_t *cmd, uint8 len)
{
  MFG_CSState key;
  key = MFG_enterCS();
  uint8_t devType = DEVICE_LOGICAL_TYPE;
  if(cmd[0] == 0)
  {
    devType = ZG_DEVICETYPE_COORDINATOR;
  }
  else if(cmd[0] == 1)
  {
    devType = ZG_DEVICETYPE_ROUTER;
  }
  else if(cmd[0] == 2)
  {
    devType = ZG_DEVICETYPE_ENDDEVICE;
  }
  zgSetItem(ZCD_NV_LOGICAL_TYPE, sizeof(devType), &devType);
  osal_nv_write(ZCD_NV_LOGICAL_TYPE, 0, sizeof(devType), &devType);
  MFG_leaveCS(key);
}

uint8_t cmdCfg_Status(void)
{
  zstack_bdbGetAttributesRsp_t bdbGetRsp;
  Zstackapi_bdbGetAttributesReq(cmdPktTaskId, &bdbGetRsp);
  if(bdbGetRsp.bdbNodeIsOnANetwork)
  {
    return ZSuccess;
  }
  return ZFailure;
}

uint8_t  cmdCfg_Channel(bool set, uint8_t ch, uint32_t *chList)
{
  zstack_bdbGetAttributesRsp_t bdbGetRsp = {0};
  Zstackapi_bdbGetAttributesReq(cmdPktTaskId, &bdbGetRsp);
  *chList = bdbGetRsp.bdbPrimaryChannelSet;
  if( bdbGetRsp.bdbNodeIsOnANetwork )
  {
    return ZFailure;
  }
  else if((ch >= 11) && (ch <= 26))
  {
    uint32_t chBit = 1<<ch;
    zstack_bdbSetAttributesReq_t bdbSetReq = {0};
    if(set == TRUE)
    {
      *chList |= chBit;
    }
    else
    {
      *chList &= ~chBit;
    }
    bdbSetReq.bdbPrimaryChannelSet = *chList;
    bdbSetReq.has_bdbPrimaryChannelSet  = TRUE;
    Zstackapi_bdbSetAttributesReq(cmdPktTaskId, &bdbSetReq);
  }
  return ZSuccess;
}

uint8_t cmdCfg_Start(void)
{
  zstack_bdbStartCommissioningReq_t startReq = {0};
  startReq.commissioning_mode = BDB_COMMISSIONING_MODE_NWK_FORMATION | BDB_COMMISSIONING_MODE_NWK_STEERING;
  return (uint8_t)Zstackapi_bdbStartCommissioningReq( cmdPktTaskId, &startReq );
}

uint8_t cmdCfg_Scan(uint32_t channel, uint8_t duration)
{
  zstack_devNwkDiscReq_t scanReq = {0};
  if(channel == 0)
  {
    channel = DEFAULT_CHANLIST;
  }
  scanReq.scanChannels = DEFAULT_CHANLIST;
  scanReq.scanDuration = duration;
  return (uint8_t)Zstackapi_DevNwkDiscReq( cmdPktTaskId, &scanReq);
}










